home *** CD-ROM | disk | FTP | other *** search
/ Die Speccy' 97 / Die Speccy' 97.iso / amiga_system / the_aminet / util / boot / snap_v2_0.lha / Snap / SnapChars.c < prev    next >
C/C++ Source or Header  |  1995-09-04  |  20KB  |  1,025 lines

  1.  
  2. #include "Snap.h"
  3.  
  4. IMPORT struct SnapRsrc *SnapRsrc;
  5.  
  6. #define COPY 0xC0L
  7. #define INVCOPY 0x30L
  8. #define CopyChar(_x, _y, _m)                                  \
  9.     BltBitMap(&MyBM, (LONG)_x, (LONG)_y,                      \
  10.       &TempBM, 0L, 0L, (LONG)FontWidth, (LONG)FontHeight,     \
  11.       _m, -1L, NULL);                                         \
  12.     WaitBlit()
  13.  
  14. WORD Unit;
  15. UWORD Pattern[5] =
  16. {
  17.     0,
  18.     0x0c3f,            /* Frame ....oo....oooooo */
  19.     0x3333,            /* Char  ..oo..oo..oo..oo */
  20.     0x1f1f,            /* Word  ...ooooo...ooooo */
  21.     0xffff            /* Line  oooooooooooooooo */
  22. };
  23.  
  24. LONG xl;            /* leftmost x position */
  25. LONG xr;            /* rightmost x position */
  26. LONG yt;            /* topmost y position */
  27. LONG yb;            /* bottommost y position */
  28. LONG minx;            /* left limit */
  29. LONG maxx;            /* right limit */
  30. LONG maxy;            /* bottom limit */
  31. LONG tl, tr;            /* used by findword - left and right edge of word */
  32. WORD fw, fh;            /* Font width and height used when drawing the frame */
  33. WORD GZZ;
  34. WORD SBM;
  35.  
  36. LONG mx, my;            /* Mouse position in character steps */
  37.  
  38. #define closetop     0
  39. #define closebottom  1
  40. WORD closey;
  41.  
  42. #define closeleft   0
  43. #define closeright  1
  44. WORD closex;
  45.  
  46.  
  47. struct Window *window;        /* The window we're snapping from */
  48.  
  49. /* Data for font being snapped */
  50. UWORD FontHeight;
  51. UWORD FontWidth;
  52. UWORD Underscore;
  53. UBYTE FontType;
  54. UBYTE LoChar;
  55. UBYTE HiChar;
  56. UWORD Modulo;
  57. UWORD *CharLoc;
  58. UWORD *CharKern;
  59. UBYTE *SrcData;
  60. IMPORT UBYTE *CharData;
  61. UBYTE IFlags;
  62.  
  63. IMPORT struct RastPort TempRp, MyRP;
  64. IMPORT struct BitMap TempBM, MyBM;
  65.  
  66. IMPORT UWORD *TempRaster;    /* Used for character recognition */
  67.  
  68. IMPORT struct Screen *theScreen;
  69. IMPORT struct RastPort rp;
  70. struct Layer *LockedLayer;
  71.  
  72. IMPORT struct timerequest MyTR;
  73.  
  74. IMPORT LONGBITS cancelsignal, donesignal, movesignal;
  75. IMPORT LONGBITS clicksignal, ticksignal, timersignal;
  76. IMPORT WORD action;
  77.  
  78. WORD starting;
  79.  
  80. /* Init vars with font data.
  81.  */
  82.  
  83. WORD SetSnapFont(font)
  84.     struct TextFont *font;
  85. {
  86.     if (!font)
  87.     {
  88.         return 0;
  89.     }
  90.     FontHeight = font->tf_YSize;
  91.     if (FontHeight > CHEIGHT)
  92.     {
  93.         return 0;
  94.     }
  95.     Underscore = font->tf_Baseline + 1;
  96.     FontType = font->tf_Flags;
  97.     if (FontType & FPF_PROPORTIONAL)
  98.     {
  99.         return 0;
  100.     }
  101.     FontWidth = font->tf_XSize;
  102.     LoChar = font->tf_LoChar;
  103.     HiChar = font->tf_HiChar;
  104.     Modulo = font->tf_Modulo;
  105.     CharLoc = (UWORD *) font->tf_CharLoc;
  106.     CharKern = (UWORD *) font->tf_CharKern;
  107.     Modulo = font->tf_Modulo;
  108.     SrcData = (UBYTE *) font->tf_CharData;
  109.     BltClear((char *)CharData, 256L * (CHEIGHT * 2), 0L);
  110.     WaitBlit();
  111.     CopyFont();
  112.     return 1;
  113. }
  114.  
  115. /* Check if the character at x, y is a space
  116.  */
  117.  
  118. WORD SnapIsSpace(x, y)
  119.     LONG x, y;
  120. {
  121.     REGISTER WORD i = FontHeight - 1;
  122.     REGISTER UWORD *data = &TempRaster[i];
  123.  
  124.     /* Copy character at x, y */
  125.     BltClear((char *)TempRaster, CHEIGHT * 2L, 0L);
  126.     ClipBlit(&rp, x, y,
  127.          &TempRp, 0L, 0L, (LONG) FontWidth, (LONG) FontHeight, COPY);
  128.     WaitBlit();
  129.  
  130.     if (*data)
  131.     {            /* Try inverted copy */
  132.         ClipBlit(&rp, x, y,
  133.              &TempRp, 0L, 0L, (LONG) FontWidth, (LONG) FontHeight, INVCOPY);
  134.         WaitBlit();
  135.     }
  136.     while (i--)
  137.     {
  138.         if (*data--)
  139.         {
  140.             return 0;
  141.         }
  142.     }
  143.     return 1;
  144. }
  145.  
  146. #define ShortFrame 4L        /* Square frame - columnar select */
  147. #define LongFrame  8L        /* Strange frame - char or word select */
  148. IMPORT LONG OFType;        /* Old frame type: ShortFrame/LongFrame */
  149. IMPORT UWORD Ptrn;
  150. IMPORT Point OldFrame[];
  151. IMPORT Point NewFrame[];
  152.  
  153.  
  154. /* update_frame calculates the new frame,
  155.    ** erases the old frame and draws the new one.
  156.    ** It's all pretty obvious if you take it slowly.
  157.  */
  158. VOID update_frame()
  159. {
  160.     LONG ft;
  161.     REGISTER LONG l, b, r, t, ml, mr;
  162.  
  163.     l = xl - 1;
  164.     r = xr + fw;
  165.     t = yt - 1;
  166.     b = yb + fh;
  167.     ml = minx - 1;
  168.     mr = maxx + fw;
  169.     if (l < 0)
  170.         l = 0;
  171.     if (r > window->Width - 1)
  172.         r = window->Width - 1;
  173.     if (t < 0)
  174.         t = 0;
  175.     if (b > window->Height - 1)
  176.         b = window->Height - 1;
  177.     if (ml < 0)
  178.         ml = 0;
  179.     if (mr > window->Width - 1)
  180.         mr = window->Width - 1;
  181.  
  182.     switch (Unit)
  183.     {
  184.     case UNIT_FRAME:
  185.         {
  186.           /*********\
  187.               *         *
  188.               *         *
  189.               \*********/
  190.             NewFrame[0].x = l;
  191.             NewFrame[0].y = t;
  192.             NewFrame[1].x = r;
  193.             NewFrame[1].y = t;
  194.             NewFrame[2].x = r;
  195.             NewFrame[2].y = b;
  196.             NewFrame[3].x = l;
  197.             NewFrame[3].y = b;
  198.             NewFrame[4].x = l;
  199.             NewFrame[4].y = t;
  200.             ft = ShortFrame;
  201.             break;
  202.         }
  203.     case UNIT_CHAR:
  204.     case UNIT_WORD:
  205.         {
  206.             if (yt == yb)
  207.             {    /* On the same line - same as UNIT_FRAME */
  208.                 NewFrame[0].x = l;
  209.                 NewFrame[0].y = t;
  210.                 NewFrame[1].x = r;
  211.                 NewFrame[1].y = t;
  212.                 NewFrame[2].x = r;
  213.                 NewFrame[2].y = b;
  214.                 NewFrame[3].x = l;
  215.                 NewFrame[3].y = b;
  216.                 NewFrame[4].x = l;
  217.                 NewFrame[4].y = t;
  218.                 ft = ShortFrame;
  219.             }
  220.             else
  221.             {
  222.               /*****\
  223.                  ******     *
  224.                  *          *
  225.                  *      *****
  226.                  *******/
  227.                 NewFrame[0].x = l;
  228.                 NewFrame[0].y = t;
  229.                 NewFrame[1].x = mr;
  230.                 NewFrame[1].y = t;
  231.                 NewFrame[2].x = mr;
  232.                 NewFrame[2].y = yb;
  233.                 NewFrame[3].x = r;
  234.                 NewFrame[3].y = yb;
  235.                 NewFrame[4].x = r;
  236.                 NewFrame[4].y = b;
  237.                 NewFrame[5].x = ml;
  238.                 NewFrame[5].y = b;
  239.                 NewFrame[6].x = ml;
  240.                 NewFrame[6].y = yt + fh;
  241.                 NewFrame[7].x = l;
  242.                 NewFrame[7].y = yt + fh;
  243.                 NewFrame[8].x = l;
  244.                 NewFrame[8].y = t;
  245.                 ft = LongFrame;
  246.             }
  247.             break;
  248.         }
  249.     case UNIT_LINE:
  250.         {
  251.             NewFrame[0].x = ml;
  252.             NewFrame[0].y = t;
  253.             NewFrame[1].x = mr;
  254.             NewFrame[1].y = t;
  255.             NewFrame[2].x = mr;
  256.             NewFrame[2].y = b;
  257.             NewFrame[3].x = ml;
  258.             NewFrame[3].y = b;
  259.             NewFrame[4].x = ml;
  260.             NewFrame[4].y = t;
  261.             ft = ShortFrame;
  262.             break;
  263.         }
  264.     default:
  265.         {
  266.             break;
  267.         }
  268.     }
  269.     draw_frame(ft);
  270. }
  271.  
  272. VOID FindWord()
  273. {
  274.     /* Must remove frame to be able to search for spaces */
  275.     WaitTOF();
  276.     erase_frame();
  277.     tl = mx;
  278.     /* Find a space to the left... */
  279.     while (!SnapIsSpace(tl, my))
  280.     {
  281.         tl -= fw;
  282.         if (tl < minx)
  283.         {
  284.             break;
  285.         }
  286.     }
  287.     tl += fw;
  288.     tr = mx;
  289.     /* ...and to the right */
  290.     while (!SnapIsSpace(tr, my))
  291.     {
  292.         tr += fw;
  293.         if (tr + fw > maxx)
  294.         {
  295.             break;
  296.         }
  297.     }
  298.     tr -= fw;
  299.     if (tr < tl)
  300.     {
  301.         tl = xl;
  302.         tr = xr;
  303.     }
  304. }
  305.  
  306. /* ChangeUnit cycles the unit of selection. The differents units
  307.    are: character, word and line.
  308.  */
  309.  
  310. VOID ChangeUnit()
  311. {
  312.  
  313.     switch (Unit)
  314.     {
  315.     case UNIT_FRAME:
  316.         {
  317.             Unit = UNIT_CHAR;
  318.             break;
  319.         }
  320.     case UNIT_CHAR:
  321.         {
  322.             Unit = UNIT_WORD;
  323.             FindWord();
  324.             xl = tl;
  325.             xr = tr;
  326.             break;
  327.         }
  328.     case UNIT_WORD:
  329.         {
  330.             Unit = UNIT_LINE;
  331.             xl = minx;
  332.             xr = maxx;
  333.             break;
  334.         }
  335.     case UNIT_LINE:
  336.         {
  337.             Unit = UNIT_FRAME;
  338.             xl = xr = mx;
  339.             break;
  340.         }
  341.     }
  342.     if (SnapRsrc->CrawlPtrn == 0)
  343.     {
  344.         Ptrn = Pattern[Unit];
  345.     }
  346. }
  347.  
  348. /* ExtendSelection extends the current selection according to
  349.    the mouse position and the selected unit.
  350.    Note that ExtendSelection doesn't optimize moves that don't
  351.    make any difference. FIXME
  352.  */
  353.  
  354. VOID ExtendSelection()
  355. {
  356.     /* Fix which row we're talking about */
  357.     if (closey == closetop)
  358.     {            /* Find closest row */
  359.         yt = my;    /* change top row */
  360.     }
  361.     else
  362.     {
  363.         yb = my;    /* change bottom row */
  364.     }
  365.  
  366.     /* Take care of left and right character pos */
  367.     switch (Unit)
  368.     {
  369.     case UNIT_FRAME:
  370.         {
  371.             if (closex == closeleft)
  372.             {
  373.                 xl = mx;
  374.             }
  375.             else
  376.             {
  377.                 xr = mx;
  378.             }
  379.             break;
  380.         }
  381.     case UNIT_CHAR:
  382.         {
  383.             if (yt == yb)
  384.             {    /* One line */
  385.                 if (closex == closeleft)
  386.                 {
  387.                     xl = mx;
  388.                 }
  389.                 else
  390.                 {
  391.                     xr = mx;
  392.                 }
  393.             }
  394.             else
  395.             {    /* Multiple lines */
  396.                 if (yt == my)
  397.                 {
  398.                     xl = mx;    /* At top - set left */
  399.                 }
  400.                 else
  401.                 {
  402.                     xr = mx;    /* At bottom - set right */
  403.                 }
  404.             }
  405.             break;
  406.         }
  407.     case UNIT_WORD:
  408.         {
  409.             FindWord();    /* Find the word */
  410.             if (yt == yb)
  411.             {    /* One line */
  412.                 if (closex == closeleft)
  413.                 {    /* Find closest char pos */
  414.                     xl = tl;
  415.                 }
  416.                 else
  417.                 {
  418.                     xr = tr;
  419.                 }
  420.             }
  421.             else
  422.             {    /* Multiple lines */
  423.                 if (yt == my)
  424.                 {    /* Where am I */
  425.                     xl = tl;    /* At top - set left */
  426.                 }
  427.                 else
  428.                 {
  429.                     xr = tr;    /* At bottom - set right */
  430.                 }
  431.             }
  432.             break;
  433.         }
  434.     case UNIT_LINE:
  435.         {        /* Always full width */
  436.             break;
  437.         }
  438.     }
  439.     if (yt - fh == yb)
  440.     {
  441.         yb += fh;
  442.     }
  443.     if (yt == yb && xl - fw == xr)
  444.     {
  445.         xr += fw;
  446.     }
  447.     if (xr > maxx)
  448.     {            /* Check for window bounds */
  449.         xr = maxx;
  450.     }
  451.     if (xl < minx)
  452.     {            /* Check for window bounds */
  453.         xl = minx;
  454.     }
  455.     if (yb > maxy)
  456.     {            /* Check for window bounds */
  457.         yb = maxy;
  458.     }
  459.     if (xl > maxx)
  460.     {
  461.         xl = maxx;
  462.     }
  463.     if (xr < minx)
  464.     {
  465.         xr = minx;
  466.     }
  467. }
  468.  
  469. /* The actual character snapper. It actually works. :-) */
  470.  
  471. WORD SnapChars()
  472. {
  473.     LONG width;
  474.     LONG height;
  475.     UBYTE *SnapSpace;
  476.     ULONG SnapSize;
  477.     ULONG counter;
  478.     REGISTER LONG x, y;
  479.  
  480.     /* Check coordinates */
  481.     if (yt - fh == yb)
  482.     {            /* No rows, shouldn't happen */
  483.         return 0;
  484.     }
  485.     if (yt == yb && xl - fw == xr)
  486.     {            /* Nothing at all */
  487.         return 0;
  488.     }
  489.  
  490.     /* Calculate stuff */
  491.     width = maxx - (minx + 1) + fw + fw;    /* Add one for a LF */
  492.     height = yb - yt + fh;
  493.     SnapSize = ((width / fw) + 1) * (height / fh);
  494.     counter = 0;
  495.  
  496.     /* Initialize things */
  497.     InitRastPort(&MyRP);
  498.     InitBitMap(&MyBM, 1L, width, height);
  499.     MyRP.BitMap = &MyBM;
  500.     SnapSpace = AllocMem(SnapSize, MEMF_PUBLIC | MEMF_CLEAR);
  501.     /* Please insert more memory */
  502.     if (!SnapSpace)
  503.     {
  504.         return 0;
  505.     }
  506.     MyBM.Planes[0] = AllocRaster(width, height);
  507.     if (!MyBM.Planes[0])
  508.     {
  509.         FreeMem(SnapSpace, SnapSize);
  510.         return 0;
  511.     }
  512.     IFlags = 0;
  513.     /* Make a local copy of the snapped chars */
  514.     ClipBlit(&rp, minx, yt, &MyRP, 0L, 0L, width, height, COPY);
  515.  
  516.     /* Ok, now we've got a copy of the character data */
  517.     /* Now it's ok to mess with the layers again */
  518.     UnlockLayer(LockedLayer);
  519.  
  520.     /* Clear our work area */
  521.     BltClear((char *)TempRaster, CHEIGHT * 2, 0L);
  522.  
  523.     /* Calculate bounds */
  524.     xl -= minx;
  525.     xr -= minx;
  526.     maxx -= minx;
  527.     minx = 0;
  528.     yb -= yt;
  529.     yt = 0;
  530.  
  531.     /* Single line - needs to be handled separately */
  532.     if (yt == yb)
  533.     {            /* Ok, we've got one */
  534.  
  535.         /* Read from left to right */
  536.         for (x = xl; x <= xr; x += fw, counter++)
  537.         {
  538.             CopyChar(x, yt, COPY);
  539.             if (!(SnapSpace[counter] = interpret(TempRaster)))
  540.             {
  541.                 SnapSpace[counter] = SnapRsrc->BadChar;        /* Unrecognized */
  542.             }
  543.         }
  544.         if (Unit == UNIT_LINE)
  545.         {
  546.             while (counter && SnapSpace[counter - 1] == ' ')
  547.             {
  548.                 counter--;
  549.             }
  550.         }
  551.     }
  552.     else
  553.     {            /* Multiple lines */
  554.  
  555.         if (Unit == UNIT_FRAME)
  556.         {
  557.             minx = xl;
  558.             maxx = xr;
  559.         }
  560.  
  561.         /* Read first line */
  562.         for (x = xl; x <= maxx; x += fw, counter++)
  563.         {
  564.             CopyChar(x, yt, COPY);
  565.             if (!(SnapSpace[counter] = interpret(TempRaster)))
  566.             {
  567.                 SnapSpace[counter] = SnapRsrc->BadChar;        /* Unrecognized */
  568.             }
  569.         }
  570.         if (Unit == UNIT_FRAME)
  571.         {
  572.             SnapSpace[counter++] = 10;
  573.         }
  574.         else
  575.         {
  576.             SHORT endspace = (SnapSpace[counter - 1] == ' ');
  577.  
  578.             /* Remove trailing blanks */
  579.             while (counter && SnapSpace[counter - 1] == ' ')
  580.             {
  581.                 counter--;
  582.             }
  583.             if (endspace || !(SnapRsrc->flags & JOINLONG))
  584.             {
  585.                 SnapSpace[counter++] = 10;
  586.             }
  587.         }
  588.  
  589.         /* If more than two rows - read full middle rows */
  590.         if (yt + fh != yb)
  591.         {
  592.             for (y = yt + fh; y < yb; y += fh)
  593.             {
  594.                 for (x = minx; x <= maxx; x += fw, counter++)
  595.                 {
  596.                     CopyChar(x, y, COPY);
  597.                     if (!(SnapSpace[counter] = interpret(TempRaster)))
  598.                     {
  599.                         SnapSpace[counter] = SnapRsrc->BadChar;        /* Unrecognized */
  600.                     }
  601.                 }
  602.                 if (Unit == UNIT_FRAME)
  603.                 {
  604.                     SnapSpace[counter++] = 10;
  605.                 }
  606.                 else
  607.                 {
  608.                     SHORT endspace = (SnapSpace[counter - 1] == ' ');
  609.  
  610.                     /* Remove trailing blanks */
  611.                     while (counter && SnapSpace[counter - 1] == ' ')
  612.                     {
  613.                         counter--;
  614.                     }
  615.                     if (endspace || !(SnapRsrc->flags & JOINLONG))
  616.                     {
  617.                         SnapSpace[counter++] = 10;
  618.                     }
  619.                 }
  620.             }
  621.         }
  622.  
  623.         /* Read last line */
  624.         for (x = minx; x <= xr; x += fw, counter++)
  625.         {
  626.             CopyChar(x, yb, COPY);
  627.             if (!(SnapSpace[counter] = interpret(TempRaster)))
  628.             {
  629.                 SnapSpace[counter] = SnapRsrc->BadChar;        /* Unrecognized */
  630.             }
  631.         }
  632.         /* Remove trailing blanks */
  633.         while (counter && SnapSpace[counter - 1] == ' ')
  634.         {
  635.             counter--;
  636.         }
  637.     }
  638.     FreeRaster(MyBM.Planes[0], width, height);
  639.     SaveClip(SnapSpace, counter);
  640.     FreeMem(SnapSpace, SnapSize);
  641.     return 1;
  642. }
  643.  
  644.  
  645. /* HandleChars is the part of the Snap state machine that handles
  646.    snapping of characters. The selection is done in different
  647.    units: char, word, line.
  648.  */
  649.  
  650. WORD HandleChars()
  651. {
  652.     LONG xoff, yoff;
  653.     LONG ox, oy;
  654.     LONG gzzx, gzzy, normalx, normaly;
  655.  
  656.     /* Find out which screen we're working on */
  657.     theScreen = WhichScreen();
  658.  
  659.     /* Oops, no screen? */
  660.     if (!theScreen)
  661.     {
  662.         action = noaction;
  663.         return 0;
  664.     }
  665.  
  666.     /* Ok, what window? */
  667.     window = WhichWindow(theScreen);
  668.  
  669.     /* Oh dear, no window. */
  670.     if (!window)
  671.     {
  672.         action = noaction;
  673.         return 0;
  674.     }
  675.  
  676.     /* Try to get these as early as possible */
  677.     gzzx = window->GZZMouseX;
  678.     gzzy = window->GZZMouseY;
  679.     normalx = window->MouseX;
  680.     normaly = window->MouseY;
  681.  
  682.     /* No messing with the layers while I think */
  683.     LockedLayer = window->WLayer;
  684.     LockLayer(0L, LockedLayer);
  685.  
  686.     /* Don't want to wreck somebody's rastport */
  687.     CopyMem((char *)window->RPort, (char *)&rp, (LONG) sizeof (struct RastPort));
  688.  
  689.     /* Or his picture */
  690.     SetDrMd(&rp, COMPLEMENT);
  691.     rp.Mask = SnapRsrc->FrameMask;
  692.  
  693.     if (window->Flags & GIMMEZEROZERO)
  694.     {
  695.         GZZ = 1;
  696.     }
  697.     else
  698.     {
  699.         GZZ = 0;
  700.     }
  701.     if (window->Flags & SUPER_BITMAP)
  702.     {
  703.         SBM = 1;
  704.     }
  705.     else
  706.     {
  707.         SBM = 0;
  708.     }
  709.  
  710.     /* Find a position */
  711.     xl = (GZZ ? gzzx : normalx) + window->RPort->Layer->Scroll_X;
  712.     yt = (GZZ ? gzzy : normaly) + window->RPort->Layer->Scroll_Y;
  713.  
  714.     if (xl < 0)
  715.     {
  716.         xl = 0;
  717.     }
  718.     if (yt < 0)
  719.     {
  720.         yt = 0;
  721.     }
  722.  
  723.     /* Check your position */
  724.     if (xl > (GZZ ? window->GZZWidth : window->Width) ||
  725.         yt > (GZZ ? window->GZZHeight : window->Height))
  726.     {
  727.         UnlockLayer(LockedLayer);
  728.         action = noaction;
  729.         return 0;
  730.     }
  731.     IFlags = 0;
  732.  
  733.     /* Find out the offset for the clicked character, if any.
  734.        ** This is the part that makes it special. Simple, isn't it. Hah!
  735.      */
  736.     {
  737.         REGISTER struct CacheWindow *cw = GetCachedWindow(theScreen, window);
  738.         struct TextFont *font[3];
  739.         WORD fonts = 0;
  740.  
  741.         /* Collect fonts to try */
  742.         if (SnapRsrc->AlternateFont)
  743.         {        /* The alternate font */
  744.             font[fonts++] = SnapRsrc->AlternateFont;
  745.         }
  746.         font[fonts++] = rp.Font;    /* Second best, the RP's font */
  747.         if (cw)
  748.         {        /* Best bet, the cached font */
  749.             font[fonts++] = cw->font;
  750.         }
  751.         while (fonts--)
  752.         {
  753.             SHORT xadj;
  754.             SHORT yadj;
  755.             SHORT seekw;
  756.             SHORT seekh;
  757.  
  758.             /* Find out what we're trying to read */
  759.             if (!SetSnapFont(font[fonts]))
  760.             {
  761.                 continue;    /* Nope, try next font */
  762.             }
  763.  
  764.             BltClear((char *)TempRaster, CHEIGHT * 2, 0L);
  765.             if (cw)
  766.             {
  767.                 xoff = -((xl - cw->xoff) % cw->fw);
  768.                 yoff = -((yt - cw->yoff) % cw->fh);
  769.                 ClipBlit(&rp, xl + xoff, yt + yoff,
  770.                      &TempRp, 0L, 0L, (LONG) FontWidth, (LONG) FontHeight, COPY);
  771.                 WaitBlit();
  772.                 if (interpret(TempRaster))
  773.                 {
  774.                     goto found;
  775.                 }
  776.             }
  777.             /* No cache or cache didn't match */
  778.             xadj = (FontWidth < 8 ? FontWidth : 8);
  779.             yadj = (FontHeight < 12 ? FontHeight : 12);
  780.             seekw = (xadj << 1) - FontWidth;
  781.             seekh = (yadj << 1) - FontHeight;
  782.             xl -= xadj;
  783.             yt -= yadj;
  784.             xoff = 0;
  785.             while (xoff < seekw)
  786.             {
  787.                 ClipBlit(&rp, xl + xoff, yt,
  788.                      &TempRp, 0L, 0L, (LONG) FontWidth, CHEIGHT, COPY);
  789.                 WaitBlit();
  790.                 yoff = 0;
  791.                 while (yoff < seekh)
  792.                 {
  793.                     if (interpret(&TempRaster[yoff]))
  794.                     {
  795.                         goto found;
  796.                     }
  797.                     ++yoff;
  798.                 }
  799.                 ++xoff;
  800.             }
  801.  
  802.             /* No character found. Try next font. */
  803.             xl += xadj;    /* Adjust to original values */
  804.             yt += yadj;
  805.         }
  806.         UnlockLayer(LockedLayer);
  807.         action = noaction;
  808.         return 0;
  809.  
  810.           found:
  811.         /* Ok, now we know where to look for chars.
  812.            ** xoff and yoff is character position within our 16xCHEIGHT bitmap.
  813.          */
  814.         xl = xl + xoff;    /* Adjust x */
  815.         yt = yt + yoff;    /* Adjust y */
  816.  
  817.         fw = FontWidth;
  818.         fh = FontHeight;
  819.  
  820.         {
  821.             SHORT temp = fh;
  822.  
  823.             while (temp <= fh + SnapRsrc->Leading)
  824.             {    /* Check for extra pixel row */
  825.                 BltClear((char *)TempRaster, CHEIGHT * 2, 0L);
  826.                 ClipBlit(&rp, xl, yt + temp,
  827.                      &TempRp, 0L, 0L, (LONG) FontWidth, (LONG) FontHeight, COPY);
  828.                 WaitBlit();
  829.                 if (interpret(TempRaster))
  830.                 {
  831.                     fh = temp;
  832.                     break;
  833.                 }
  834.                 ++temp;
  835.             }
  836.         }
  837.  
  838.         /* Find out offsets within the window */
  839.         xoff = xl % fw;
  840.         yoff = yt % fh;
  841.  
  842.         if (cw)
  843.         {
  844.             cw->xoff = xoff;
  845.             cw->yoff = yoff;
  846.             cw->fw = fw;
  847.             cw->fh = fh;
  848.             cw->font = font[fonts];
  849.         }
  850.         else
  851.         {
  852.             CacheWindow(window, xoff, yoff, fw, fh, font[fonts]);
  853.         }
  854.     }
  855.  
  856.     /* Set bounds */
  857.     minx = xoff;
  858.     maxx = minx +
  859.         (((GZZ ?
  860.            window->GZZWidth :
  861.            window->Width - window->BorderRight
  862.     /* Hack for borderless conman windows */
  863.            + (window->Flags & BORDERLESS && window->Flags & WINDOWSIZING ? 14 : 0))
  864.           - minx - fw) / fw) * fw;
  865.     maxy = yoff +
  866.         (((GZZ ? window->GZZHeight : window->Height) - yoff - fh) / fh) * fh;
  867.  
  868.     /* Check bounds */
  869.     if (xl > maxx)
  870.     {
  871.         UnlockLayer(LockedLayer);
  872.         action = noaction;
  873.         return 0;
  874.     }
  875.     /* Set box dimensions */
  876.     xr = xl;
  877.     yb = yt;
  878.     ox = xr;
  879.     oy = yt;
  880.  
  881.     /* Select unit while starting */
  882.     starting = 1;
  883.  
  884.     /* Starting unit is character or frame */
  885.     Unit = SnapRsrc->StartUnit;
  886.     Ptrn = (SnapRsrc->CrawlPtrn ? SnapRsrc->CrawlPtrn : Pattern[Unit]);
  887.     OFType = 0L;
  888.     update_frame();
  889.  
  890.     /* Get the state machine running */
  891.     FOREVER
  892.     {
  893.         /* Wait for something to happen */
  894.         REGISTER LONGBITS sig;
  895.  
  896.         MyTR.tr_time.tv_secs = 0;
  897.         MyTR.tr_time.tv_micro = 500000;
  898.         MyTR.tr_node.io_Command = TR_ADDREQUEST;
  899.         SendIO((struct IORequest *)&MyTR);
  900.  
  901.         sig = Wait(movesignal | cancelsignal | donesignal |
  902.                clicksignal | ticksignal | timersignal);
  903.  
  904.         if ((sig & timersignal) && CheckIO((struct IORequest *)&MyTR))
  905.         {
  906.             WaitIO((struct IORequest *)&MyTR);
  907.             erase_frame();
  908.             UnlockLayer(LockedLayer);    /* Unlock things */
  909.             sig = Wait(ticksignal);        /* Wait for input handler to become avtive */
  910.             LockLayer(0L, LockedLayer);    /* Re-lock */
  911.             /* I guess I should check to see that the window is still
  912.                there. Aw, what the heck. Apologies to anyone who gets
  913.                bitten by this. */
  914.             DisplayBeep(NULL);
  915.             update_frame();
  916.         }
  917.         else
  918.         {
  919.             AbortIO((struct IORequest *)&MyTR);
  920.             WaitIO((struct IORequest *)&MyTR);
  921.             SetSignal(0, timersignal);
  922.         }
  923.  
  924.         if ((sig & ticksignal) && (SnapRsrc->CrawlPtrn != 0xffff))
  925.         {
  926.             crawl_frame(0L);
  927.         }
  928.  
  929.         mx = (LONG) (GZZ ? window->GZZMouseX : window->MouseX)
  930.             + window->RPort->Layer->Scroll_X;
  931.         if (mx < 0)
  932.         {
  933.             mx = 0;
  934.         }
  935.         /* Calculate which edge is closest */
  936.         if ((mx - xl) < (xr - mx))
  937.         {
  938.             closex = closeleft;
  939.         }
  940.         else
  941.         {
  942.             closex = closeright;
  943.         }
  944.         /* Only interested in real char pos */
  945.         mx = mx - ((mx - xoff) % fw);
  946.  
  947.         my = (LONG) (GZZ ? window->GZZMouseY : window->MouseY)
  948.             + window->RPort->Layer->Scroll_Y;
  949.         if (my < 0)
  950.         {
  951.             my = 0;
  952.         }
  953.         /* Calculate which row is closest */
  954.         if ((my - yt) < (yb - my))
  955.         {
  956.             closey = closetop;
  957.         }
  958.         else
  959.         {
  960.             closey = closebottom;
  961.         }
  962.         my = my - ((my - yoff) % fh);
  963.  
  964.         /* Hey, it moves! It's alive!! */
  965.         if ((sig & movesignal) && (action == snaptext))
  966.         {
  967.             if (mx != ox || my != oy)
  968.             {    /* Something's happened */
  969.                 ExtendSelection();
  970.                 update_frame();
  971.                 starting = 0;
  972.                 ox = mx;
  973.                 oy = my;
  974.                 sig &= ~clicksignal;
  975.             }
  976.         }
  977.  
  978.         /* Ok, forget it... */
  979.         if (sig & cancelsignal)
  980.         {
  981.             erase_frame();
  982.             UnlockLayer(LockedLayer);
  983.             return 0;
  984.         }
  985.  
  986.         /* Click */
  987.         if ((sig & clicksignal) && (action == snaptext))
  988.         {
  989.             /* Selecting unit */
  990.             if (starting)
  991.             {
  992.                 if (mx == ox && my == oy)
  993.                 {
  994.                     ChangeUnit();
  995.                     if (Unit == UNIT_CHAR)
  996.                     {
  997.                         ChangeUnit();
  998.                     }
  999.                     update_frame();
  1000.                 }
  1001.                 else if (Unit == UNIT_FRAME)
  1002.                 {
  1003.                     ChangeUnit();
  1004.                     update_frame();
  1005.                 }
  1006.             }
  1007.             if (mx != ox || my != oy)
  1008.             {    /* Click in a new place */
  1009.                 ExtendSelection();
  1010.                 update_frame();
  1011.                 starting = 0;
  1012.                 ox = mx;
  1013.                 oy = my;
  1014.             }
  1015.         }
  1016.  
  1017.         /* Finished */
  1018.         if (sig & donesignal)
  1019.         {
  1020.             erase_frame();
  1021.             return SnapChars();
  1022.         }
  1023.     }
  1024. }
  1025.